package net.csdn.business.framework.error.handler;

import cn.hutool.core.exceptions.ValidateException;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import net.csdn.business.common.enums.ResultCodeEnum;
import net.csdn.business.common.exception.BusinessException;
import net.csdn.business.common.utils.JsonUtil;
import net.csdn.business.common.utils.ResponseResultUtil;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingRequestValueException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

/**
 * @author likun
 * @date 2022/6/8 15:49
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ResponseBody
    @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
    public ResponseEntity<?> handleValidException(Exception e) {
        e.printStackTrace();
        BindingResult result = null;
        if (e instanceof MethodArgumentNotValidException) {
            result = ((MethodArgumentNotValidException) e).getBindingResult();
        } else if (e instanceof BindException) {
            result = ((BindException) e).getBindingResult();
        }
        if (null == result) {
            return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.PARAMETER_ERROR);
        }
        for (ObjectError error : result.getAllErrors()) {
            return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.PARAMETER_ERROR.name(), error.getDefaultMessage());
        }
        return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.PARAMETER_ERROR);
    }

    @ResponseBody
    @ExceptionHandler({ValidateException.class})
    public ResponseEntity<?> handlerValidateException(ValidateException e) {
        e.printStackTrace();
        return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.PARAMETER_ERROR_CUSTOM.name(), e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler({BusinessException.class})
    public ResponseEntity<?> handleBizException(BusinessException e) {
        e.printStackTrace();
        log.warn("handleBizException e:{}", JsonUtil.toJsonString(e));
        return ResponseResultUtil.buildErrorResponse(e.getCode(), e.getResultCodeName(), e.getMsg());
    }

    @ResponseBody
    @ExceptionHandler({Throwable.class})
    public ResponseEntity<?> handleThrowable(Throwable e) {
        e.printStackTrace();
        log.error("handleThrowable error:{}", JsonUtil.toJsonString(e));
        return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.FAIL);
    }

    @ResponseBody
    @ExceptionHandler({FeignException.class})
    public ResponseEntity<?> handleFeignException(Exception e) {
        e.printStackTrace();
        log.error("handleFeignException e:{}", JsonUtil.toJsonString(e));
        if (e.getCause() instanceof BusinessException) {
            BusinessException be = (BusinessException) e.getCause();
            return ResponseResultUtil.buildErrorResponse(be.getCode(), be.getResultCodeName(), be.getMsg());
        }
        return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.FAIL);
    }

    @ResponseBody
    @ExceptionHandler({Exception.class})
    public ResponseEntity<?> handleException(Exception e) {
        e.printStackTrace();
        try {
            log.error("handleException e:{}", JsonUtil.toJsonString(e));
        } catch (Exception e1) {
            log.error("handleException e:{}", e.getMessage());
        }
        return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.FAIL);
    }

    @ResponseBody
    @ExceptionHandler({MissingRequestValueException.class})
    public ResponseEntity<?> handleMissRequestException(MissingRequestValueException e) {
        e.printStackTrace();
        log.warn("handleMissingRequestValueException e:{}", JsonUtil.toJsonString(e));
        return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.BAD_REQUEST, e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public ResponseEntity<?> handleNotSupportException(HttpRequestMethodNotSupportedException e) {
        e.printStackTrace();
        log.warn("handleHttpRequestMethodNotSupportedException e:{}", JsonUtil.toJsonString(e));
        return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.METHOD_NOT_ALLOWED, e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler({NoHandlerFoundException.class})
    public ResponseEntity<?> handleNoHandlerFoundException(NoHandlerFoundException e) {
        e.printStackTrace();
        return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.NOT_PATH, e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler({DataIntegrityViolationException.class})
    public ResponseEntity<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
        e.printStackTrace();
        log.warn("handleDataIntegrityViolationException e:{}", e.getMessage());
        e.printStackTrace();
        return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.FAIL);
    }

    @ResponseBody
    @ExceptionHandler({InvalidDataAccessResourceUsageException.class})
    public ResponseEntity<?> handleDataAccessException(InvalidDataAccessResourceUsageException e) {
        e.printStackTrace();
        if (e instanceof BadSqlGrammarException) {
            log.error("handleDataAccess s:{} e:{}", ((BadSqlGrammarException) e).getSql(), e.getMessage());
        } else {
            log.error("handleDataAccess e:{}", e.getMessage());
        }
        return ResponseResultUtil.buildErrorResponse(ResultCodeEnum.FAIL);
    }
}